////////////////////////////////////////////////
// DESCRIPTION:
//    Win32 HANDLE wrapper template class
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

#include <windows.h>

namespace FusionWare
{
	namespace Win32
	{
        // {Internal}
        class RefCountingPolicy
        {
        protected:
            RefCountingPolicy()
                : pRefCount(NULL)
            {}

            ~RefCountingPolicy()
            {
                ASSERT(this->pRefCount == NULL);
            }

            void Create()
            {
                ASSERT(NULL == this->pRefCount);
                this->pRefCount = new long;
                if(this->pRefCount != NULL)
                    (*(this->pRefCount)) = 1;
            }

            bool Release()
            {
                // release resource only if ref count goes to zero
                if(this->pRefCount && (0 == InterlockedDecrement(pRefCount)))
                {
                    delete pRefCount;
                    pRefCount = NULL;
                    return true;
                }
                
                // disconnect this instance from the count
                pRefCount = NULL;
                return false;
            }
    
            void Copy(const RefCountingPolicy& p)
            {
                ASSERT(pRefCount == NULL);

                pRefCount = p.pRefCount;
                if(pRefCount!=NULL)
                {
                    ASSERT(*pRefCount > 0);
        
                    InterlockedIncrement(pRefCount);
                }
            }
  
        protected:
            long* pRefCount;
        };

        /////////////////////////////////////////////////////////
        // Wrapper class around a Win32 Handle
        // 
        // Remarks:
        //     This class is designed to provide a standard
        //     functionality in a base class for specifc types
        //     of handles. It cannot be used standalone, thus
        //     the constructor and destructor are protected
        //     as well as some other member functions.
        //
        // Implementation Notes:
        //     Since CE v5.0 does not support DuplicateHandle for all
        //     handle types this uses a Copy Policy that is
        //     reference counted to allow copy/assignement semantics.
        //     This could be updated in the future to use a different
        //     copy policy  for those handle types that do support 
        //     DuplicateHandle without effecting code that uses the
        //     derived handle types.
        //
        template <HANDLE InvalidHandleValue, class CopyPolicy = RefCountingPolicy>
        class TWin32Handle : private  CopyPolicy
        {
        public:
            // checks for a valid handle (INVALID_HANDLE_VALUE is ALWAYS invalid)
            bool IsValid() const     { return this->Win32Handle!=InvalidHandleValue && this->Win32Handle!=INVALID_HANDLE_VALUE; }
            operator !() const       { return !IsValid(); }
            
            TWin32Handle<InvalidHandleValue>& operator=(HANDLE h)
            {
                Close();
                Win32Handle = h;
                CopyPolicy::Create();
                return *this;
            }

            TWin32Handle<InvalidHandleValue>& operator=(const TWin32Handle<InvalidHandleValue>& Src)
            {
                CopyPolicy::Copy(Src);
                Win32Handle = Src.Win32Handle;
                return *this;
            }

            // Close the handle
            bool Close()
            {
                bool retVal = true;
                if(CopyPolicy::Release() && IsValid())
                    retVal = 0!=::CloseHandle(Win32Handle);
        
                Win32Handle = InvalidHandleValue;
                return retVal;
            };

            // NOTE: 
            //    This should be used sparingly, the only really valid use
            //    is to set up an array of handles for WaitForMultipleObjects()
            //    and only then when the lifetime of the original object
            //    this method is called on has a lifetime that out lasts
            //    the wait.
            //
            HANDLE GetHandle() const { return Win32Handle; }
            
        protected:
            HANDLE Detach()        { return CopyPolicy::Release(); }

            HANDLE Win32Handle;

            ///////////////////////////////////////////////////////
            // Description: 
            //    Waits for the Handle
            //
            // Input: 
            //    TimeOut [Default = INFINITE] Time in milliseconds to wait 
            //
            // Returns: 
            //     WAIT_OBJECT_0 Event was triggered
            //     WAIT_TIMEOUT  Timeout occured waiting for the object 
            //     WAIT_FAIL     Event Handle was bad
            //     
            // Implementation Note:
            //    Protected as not all handles can be used with
            //    WaitForSingleObject
            //
            DWORD Wait(DWORD TimeOut=INFINITE)
            {
                return WaitForSingleObject(this->Win32Handle, TimeOut);
            }

            // protected constructors to prevent creation of a non specific handle

            TWin32Handle()
            : Win32Handle(InvalidHandleValue)
            {}
        
            TWin32Handle(HANDLE h)
                : Win32Handle(h) 
            {
                CopyPolicy::Create();
            }

            TWin32Handle(const TWin32Handle<InvalidHandleValue, CopyPolicy>& Src)
                : Win32Handle(Src.Win32Handle) 
            {
                CopyPolicy::Copy(Src);
            }
            
            ~TWin32Handle()
            {
                Close();
            }
        };
	}
}